<?php

namespace app\common\service\core;

use app\common\enums\AccountTypeEnum;
use app\common\enums\core\PayTypeEnum;
use app\common\enums\TcScheduleStatusEnum;
use app\common\enums\TrialClassOrderStatusEnum;
use app\common\model\banxi\core\CoreTrialClassConfig;
use app\common\model\banxi\core\CoreTrialClassOrder;
use app\common\model\banxi\Grade;
use app\common\model\banxi\student\Student;
use app\common\service\ApiService;
use app\common\service\pay\AlipayService;
use app\common\service\pay\WxPayService;
use app\common\service\qrcode\QrcodeService;
use app\common\service\SnowflakeService;

class TrialClassOrderService extends ApiService
{
    /**
     * 下单
     */
    public function place($studentId, $data, $creater)
    {
        $expectTime = $data['expectTime'];
        $currentTime = time();
        $threeHoursLater = strtotime('+3 hours', $currentTime);
        if ($threeHoursLater > strtotime($expectTime)) {
            getResponseException("期望上课时间过近，最低选择当前时间+3小时", [], 1, 'ERROR');
        }
        $studentModel = new Student();
        $student = $studentModel->where('id', $studentId)->find();
        if (empty($student)) {
            getResponseException("账号异常，发起支付失败", [], 1, 'ERROR');
        }
        $coreTrialClassConfigModel = new CoreTrialClassConfig();
        $trialClassConfig = $coreTrialClassConfigModel->getConfigInfo();
        if (empty($trialClassConfig)) {
            getResponseException("体验课暂时不可进行购买", [], 1, 'ERROR');
        }
        $trialClassOrderModel = new CoreTrialClassOrder();
        // $count = $trialClassOrderModel->countPayByStudent($studentId);
        // if ($count >= 1) {
        //     getResponseException("您的购买次数已达上限，请勿重复购买", [], 1, 'ERROR');
        // }
        $gradeId = $student['gradeId'];
        $grade = $gradeId ? Grade::where('id', $gradeId)->find() : null;
        $snowflakeService = new SnowflakeService(1, 1);
        $orderId = $snowflakeService->nextId();
        $trialClassOrder = [
            'id' => $orderId,
            'studentId' => $studentId,
            'organizationId' => $student['organizationId'],
            'price' => $trialClassConfig['price'],
            'payPrice' => $trialClassConfig['price'],
            'childName' => $student['name'],
            'phone' => $student['phone'],
            'gradeName' => empty($grade) ? '已删除' : $grade['name'],
            'englishScore' => $student['englishScore'],
            'expectTime' => $expectTime,
            'orderStatus' => TrialClassOrderStatusEnum::WAIT_PAY,
            'creater' => $creater,
            'remark' => $data['remark'] ?? ''
        ];
        $trialClassOrderModel->cancelByStudent($studentId);
        $trialClassOrderModel->save($trialClassOrder);
        return $trialClassOrderModel->id;
    }

    /**
     * 发起支付 $environment pc or wx
     */
    /**
     * 发起支付 $environment pc or wx
     */
    public function payInitiate($studentId, $orderId, $payType, $environment)
    {
        // 参数验证
        if (!in_array($payType, [PayTypeEnum::WECHAT, PayTypeEnum::ALIPAY, PayTypeEnum::SIMULATED_PAYMENT])) {
            getResponseException("暂不支持此支付方式", [], 1, 'ERROR');
        }

        $trialClassOrderModel = new CoreTrialClassOrder();
        $orderInfo = $trialClassOrderModel->where(['id' => $orderId])->find();

        // 订单验证
        if (empty($orderInfo) || $orderInfo['studentId'] != $studentId) {
            getResponseException("订单不存在", [], 1, 'ERROR');
        }

        // 订单状态验证
        switch ($orderInfo['orderStatus']) {
            case TrialClassOrderStatusEnum::SUCCESS_PAY:
                getResponseException("订单已支付", [], 1, 'ERROR');
            case TrialClassOrderStatusEnum::FAIL_PAY:
                getResponseException("订单支付失败，请勿重新发起支付", [], 1, 'ERROR');
            case TrialClassOrderStatusEnum::CANCEL:
                getResponseException("订单已作废，请勿重新发起支付", [], 1, 'ERROR');
        }

        $studentModel = new Student();
        $student = $studentModel->where('id', $studentId)->find();
        if (empty($student)) {
            getResponseException("账号异常，发起支付失败", [], 1, 'ERROR');
        }

        // 微信支付需要绑定openid
        if ($payType === PayTypeEnum::WECHAT && empty($student['weMiniOpenid'])) {
            getResponseException("请先绑定微信", [], 1, 'ERROR');
        }

        $payParams = null;
        switch ($payType) {
            case PayTypeEnum::WECHAT:
                $futureTime = strtotime('+60 minutes');
                $wxPayService = new WxPayService();
                if ($environment !== 'pc') {
                    $payParams = $wxPayService->jsApiPay(
                        $student['weMiniOpenid'],
                        '体验课购买',
                        null,
                        $orderId,
                        $orderInfo['payPrice'],
                        '/common_api/core/coreTrialClassOrder/payCallWechat',
                        $futureTime
                    );
                } else {
                    $payParams = $wxPayService->nativePay(
                        '体验课购买',
                        null,
                        $orderId,
                        $orderInfo['payPrice'],
                        '/common_api/core/coreTrialClassOrder/payCallWechat',
                        $futureTime
                    );
                    $qrcodeService = new QrcodeService();
                    $payParams = $qrcodeService->generate(
                        $payParams,
                        ['width' => 200, 'height' => 200]
                    );
                }
                break;

            case PayTypeEnum::ALIPAY:
                if ($environment === 'pc') {
                    $alipayService = new AlipayService();
                    $payParams = $alipayService->scanCodePay(
                        $orderId,
                        $orderInfo['payPrice'],
                        '体验课购买',
                        '/common_api/core/coreTrialClassOrder/payCallAlipay'
                    );
                    $qrcodeService = new QrcodeService();
                    $payParams = $qrcodeService->generate(
                        $payParams,
                        ['width' => 200, 'height' => 200]
                    );
                } else {
                    getResponseException("暂不支持此支付方式", [], 1, 'ERROR');
                }
                break;

            case PayTypeEnum::SIMULATED_PAYMENT:
                $this->payCall($orderId, $orderInfo['payPrice'], null, $payType);
                break;
        }

        return [
            'orderId' => $orderInfo['id'],
            'payType' => $payType,
            'payParams' => $payParams
        ];
    }


    /**
     * 支付回调
     */

    public function payCall($orderId, $payAmount, $payNumber, $payType)
    {
        $coreTrialClassOrderModel = new CoreTrialClassOrder();
        $orderInfo = $coreTrialClassOrderModel->where(['id' => $orderId])->find();
        if (empty($orderInfo)) {
            logSave([
                'orderId' => $orderId,
                'payAmount' => $payAmount,
                'payNumber' => $payNumber,
                'payType' => $payType,
                'message' => '订单回调支付警告，订单不存在'
            ], 'payCall', 'TrialClassOrderService');
            return true;
        }
        $state = $orderInfo['orderStatus'];
        if ($state == TrialClassOrderStatusEnum::SUCCESS_PAY) {
            logSave([
                'orderId' => $orderId,
                'payAmount' => $payAmount,
                'payNumber' => $payNumber,
                'payType' => $payType,
                'orderInfo' => json_encode($orderInfo, true),
                'message' => '订单回调支付警告，订单已支付，订单号'
            ], 'payCall', 'TrialClassOrderService');
            return true;
        }
        $updateQueryWrapper = $coreTrialClassOrderModel->where([
            'id' => $orderId,
            'orderStatus' => $state
        ]);
        if ($state == TrialClassOrderStatusEnum::CANCEL || $state == TrialClassOrderStatusEnum::FAIL_PAY) {
            logSave([
                'orderId' => $orderId,
                'payAmount' => $payAmount,
                'payNumber' => $payNumber,
                'payType' => $payType,
                'orderInfo' => json_encode($orderInfo, true),
                'message' => '订单回调支付警告，订单状态异常'
            ], 'payCall', 'TrialClassOrderService');
            $updateQueryWrapper->update([
                'payNo' => $payNumber,
                'payType' => $payType,
                'orderStatus' => TrialClassOrderStatusEnum::FAIL_PAY,
                'payTime' => date('Y-m-d H:i:s'),
                'payFailReason' => '订单状态异常，支付回调失败',
            ]);
            return true;
        }
        $amount = $orderInfo['payPrice'];
        if ($payAmount != null && $amount != $payAmount) {
            logSave([
                'orderId' => $orderId,
                'payAmount' => $payAmount,
                'payNumber' => $payNumber,
                'payType' => $payType,
                'orderInfo' => json_encode($orderInfo, true),
                'message' => '订单回调支付警告，订单金额不匹配'
            ], 'payCall', 'TrialClassOrderService');
            $updateQueryWrapper->update([
                'payNo' => $payNumber,
                'payType' => $payType,
                'orderStatus' => TrialClassOrderStatusEnum::FAIL_PAY,
                'payTime' => date('Y-m-d H:i:s'),
                'payFailReason' => '订单金额不匹配，支付回调失败 支付金额' . $payAmount,
            ]);
            return true;
        }
        $scheduleStatus = $orderInfo['creater'] == AccountTypeEnum::STUDENT ? TcScheduleStatusEnum::E1 : TcScheduleStatusEnum::E2;
        $cnt = $updateQueryWrapper->update([
            'payNo' => $payNumber,
            'payType' => $payType,
            'orderStatus' => TrialClassOrderStatusEnum::SUCCESS_PAY,
            'scheduleStatus' => $scheduleStatus,
            'payTime' => date('Y-m-d H:i:s'),
        ]);
        if (!$cnt) {
            logSave([
                'orderId' => $orderId,
                'payAmount' => $payAmount,
                'payNumber' => $payNumber,
                'payType' => $payType,
                'orderInfo' => json_encode($orderInfo, true),
                'message' => '订单回调支付警告，订单修改支付状态失败'
            ], 'payCall', 'TrialClassOrderService');
            getResponseException('订单支付失败', [], 1, 'ERROR');
        }
        return true;
    }
}
